#pragma once
#include "Common.h"
#include "MemoryMgr.h"

namespace WL
{
	class CComponent
	{
	public:
		CComponent() = default;
		virtual ~CComponent();
		const std::string& getComponentName() const;
		void setComponentName(const std::string& szName);
		
	protected:
		std::string mComponentName = "Component";
	};


	//////////////////////////////////////////////////////////////////////////
	struct ComponentGrounp
	{
		//////////////////////////////////////////////////////////////////////////
		//Function
		ComponentGrounp() = default;
		virtual ~ComponentGrounp();

		void addComponent(CComponent* pComponent)
		{
			if (nullptr != pComponent)
			{
				auto szName = pComponent->getComponentName();
				auto iter = mComponent.find(szName);
				if (mComponent.end() == iter)
				{
					mComponent[szName] = pComponent;
				}
				else
				{
					SafeDelete(iter->second);
					mComponent[szName] = pComponent;
				}
			}
		}

		template<typename T>
		void addComponent()
		{
			auto pComponent = WL_NEW(T, Component);
			addComponent(pComponent);
		}

		template<typename T0, typename T1>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
		}

		template<typename T0, typename T1, typename T2>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
		}

		template<typename T0, typename T1, typename T2, typename T3>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
			addComponent<T3>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
			addComponent<T3>();
			addComponent<T4>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
			addComponent<T3>();
			addComponent<T4>();
			addComponent<T5>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
			addComponent<T3>();
			addComponent<T4>();
			addComponent<T5>();
			addComponent<T6>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
			addComponent<T3>();
			addComponent<T4>();
			addComponent<T5>();
			addComponent<T6>();
			addComponent<T7>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
			addComponent<T3>();
			addComponent<T4>();
			addComponent<T5>();
			addComponent<T6>();
			addComponent<T7>();
			addComponent<T8>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
		void addComponent()
		{
			addComponent<T0>();
			addComponent<T1>();
			addComponent<T2>();
			addComponent<T3>();
			addComponent<T4>();
			addComponent<T5>();
			addComponent<T6>();
			addComponent<T7>();
			addComponent<T8>();
			addComponent<T9>();
		}

		void removeComponent(CComponent* pComponet)
		{
			auto iter = mComponent.begin();
			auto iterEnd = mComponent.end();
			while (iter != iterEnd)
			{
				if (iter->second == pComponet)
				{
					WL_DELETE(iter->second, Component);
					mComponent.erase(iter);
					break;
				}
				else
				{
					++iter;
				}
			}
		}

		template<typename T>
		void removeComponent()
		{
			auto iter = mComponent.begin();
			auto iterEnd = mComponent.end();
			while (iter != iterEnd)
			{
				if (nullptr != dynamic_cast<T*>(iter->second))
				{
					WL_DELETE(iter->second, Component);
					mComponent.erase(iter);
					break;
				}
				else
				{
					++iter;
				}
			}
		}

		template<typename T0, typename T1>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
		}

		template<typename T0, typename T1, typename T2>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
		}

		template<typename T0, typename T1, typename T2, typename T3>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
			removeComponent<T3>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
			removeComponent<T3>();
			removeComponent<T4>();
		}
		
		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
			removeComponent<T3>();
			removeComponent<T4>();
			removeComponent<T5>();
		}
		
		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
			removeComponent<T3>();
			removeComponent<T4>();
			removeComponent<T5>();
			removeComponent<T6>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
			removeComponent<T3>();
			removeComponent<T4>();
			removeComponent<T5>();
			removeComponent<T6>();
			removeComponent<T7>();
		}
		
		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
			removeComponent<T3>();
			removeComponent<T4>();
			removeComponent<T5>();
			removeComponent<T6>();
			removeComponent<T7>();
			removeComponent<T8>();
		}

		template<typename T0, typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9>
		void removeComponent()
		{
			removeComponent<T0>();
			removeComponent<T1>();
			removeComponent<T2>();
			removeComponent<T3>();
			removeComponent<T4>();
			removeComponent<T5>();
			removeComponent<T6>();
			removeComponent<T7>();
			removeComponent<T8>();
			removeComponent<T9>();
		}

		template< typename T>
		T* getComponent();

		CComponent* getComponetByName(const std::string& szName);

		//////////////////////////////////////////////////////////////////////////
		//Data
		std::map<std::string, CComponent*> mComponent;
	};


	template< typename T>
	T* ComponentGrounp::getComponent()
	{
		T* pComponent = nullptr;
		for (auto item : mComponent)
		{
			pComponent = dynamic_cast<T*>(item.second);
			if (nullptr != pComponent)
			{
				break;
			}
		}
		return pComponent;
	}
}